package com.gistmap.ntdc.service;

import com.gistmap.ntdc.exception.ErrorItems;
import com.gistmap.ntdc.exception.ServiceException;
import com.gistmap.ntdc.model.MenuVO;
import com.gistmap.ntdc.model.ProductVO;
import com.gistmap.ntdc.persistence.domain.Category;
import com.gistmap.ntdc.persistence.domain.Product;
import com.gistmap.ntdc.persistence.repo.CategoryRepository;
import com.gistmap.ntdc.persistence.repo.ProductRepository;
import com.google.common.collect.Lists;
import com.thoughtworks.xstream.core.BaseException;
import org.modelmapper.ModelMapper;
import org.modelmapper.TypeToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * @author zhangran
 * @date 2018/12/12
 */
@Component
@Transactional(rollbackFor = ServiceException.class)
public class ProductService {

    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private CategoryRepository categoryRepository;

    public Product find(Long id){
        return productRepository.findById(id).orElseThrow(() -> new ServiceException(ErrorItems.PRODUCT_NOT_EXIST));
    }

    @Cacheable("menus")
    public List<MenuVO> findAll() {
        List<MenuVO> menus = Lists.newArrayList();
        Map<Category, List<Product>> collect = productRepository.findAll()
                .stream()
                .collect(Collectors.groupingBy(Product::getCategory));
        Map<Category, List<Product>> categoryListMap = sortMapByKey(collect);
        categoryListMap.forEach( (k,v) -> {
            MenuVO menuVO = new MenuVO();
            menuVO.name = k.getName();
            menuVO.foods = convert2Vo(v);
            menus.add(menuVO);
        });
        return menus;
    }

    /**
     * 加减库存
     *
     * @param id    商品 ID
     * @param count 加减库存的数量
     * @param add   true为加，false为减
     * @return 返回操作结束的库存数，-1为失败
     */
    protected void operateStock(Long id, Integer count, boolean add) {
        int latestCount;
        Product product = find(id);
        if (add) {
            latestCount = product.getStock() + count;
        } else {
            if (count > product.getStock()) {
                throw new ServiceException(ErrorItems.STOCK_NOT_LEGAL);
            }
            latestCount = product.getStock() - count;
        }
        product.setStock(latestCount);
        productRepository.save(product);
    }

    private List<ProductVO> convert2Vo(List<Product> list){
        ModelMapper mapper = new ModelMapper();
        return mapper.map(list, new TypeToken<List<ProductVO>>() {}.getType());
    }

    /**
     * 让 Map按key进行排序
     */
    private static Map<Category, List<Product>> sortMapByKey(Map<Category, List<Product>> map) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        Map<Category, List<Product>> sortMap = new TreeMap<>(new MapKeyComparator());
        sortMap.putAll(map);
        return sortMap;
    }



    static class MapKeyComparator implements Comparator<Category> {

        @Override
        public int compare(Category s1, Category s2) {
            return s1.getSeq().compareTo(s2.getSeq());
        }
    }
}
